<!-- 黄金矿工 -->
<template>
  <div class="game-container">
    <div class="controls">
      <button @click="startGame" :disabled="isGameRunning">开始游戏</button>
      <button @click="resetGame">重置</button>
      <button @click="togglePause">{{ isPaused ? '继续' : '暂停' }}</button>
      <div class="timer">时间: {{ timeLeft }}s</div>
      <div class="score">分数: {{ score }}</div>
    </div>
    <div ref="gameCanvas" class="game-canvas"></div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import * as PIXI from 'pixi.js'
import confetti from 'canvas-confetti'

// 游戏状态
const isGameRunning = ref(false)
const isPaused = ref(false)
const timeLeft = ref(60)
const score = ref(0)
const gameCanvas = ref<HTMLDivElement | null>(null)

// PixiJS 相关变量
let app: PIXI.Application
let miner: PIXI.Container
let hook: PIXI.Sprite
let rope: PIXI.Graphics
let fireButton: PIXI.Container
let minerals: PIXI.Graphics[] = []
let gameInterval: PIXI.TickerCallback<TypeValue>
let timerInterval: number
let hookAngle = Math.PI / 2 // 初始角度（指向正下方）
const swingRadius = 50 // 摆动半径
const angularSpeed = 0.03 // 角速度
let direction = 1 // 方向：1 表示顺时针，-1 表示逆时针
let hookState: 'swinging' | 'extending' | 'retracting' | 'caught' = 'swinging'
let caughtMineral: PIXI.Graphics | null = null
const hookSpeed = 5
let minerAnimationFrame = 0
const canvasWidth = 375
const canvasheight = 800
const platformHeight = 20
const minerBodyStyle = { w: 80, h: 80 } // 矿工身体
const minerDown = { x: 20, y: 110 } // 矿工底部位置

// 初始化游戏
const initGame = async () => {
  if (!gameCanvas.value) return

  // 创建 PixiJS 应用
  app = new PIXI.Application()

  await app.init({
    width: canvasWidth,
    height: canvasheight,
    backgroundColor: 0xfda085,
    antialias: true,
  })
  gameCanvas.value.appendChild(app.canvas as HTMLCanvasElement)

  // 创建顶部平台
  const platform = new PIXI.Graphics()
  platform.rect(0, 0, canvasWidth, platformHeight)
  platform.fill(0x8b4513)
  app.stage.addChild(platform)

  // 创建矿工 (放在顶部)
  miner = new PIXI.Container()
  // 加载资源（确保路径正确）
  await PIXI.Assets.load('/assets/image/miner.png');
  const minerBody = PIXI.Sprite.from('/assets/image/miner.png');
  minerBody.x = -20
  minerBody.y = 0
  minerBody.width = minerBodyStyle.w
  minerBody.height = minerBodyStyle.h
  miner.addChild(minerBody)

  const minerHead = new PIXI.Graphics()
  minerHead.circle(20, -10, 15)
  minerHead.fill(0xffd700)
  miner.addChild(minerHead)

  miner.position.set(canvasWidth / 2 - 20, platformHeight + 20) // 矿工在顶部
  app.stage.addChild(miner)

  // 创建钩子 (方向朝下)
  await PIXI.Assets.load('/assets/image/hook.png');
  hook = PIXI.Sprite.from('/assets/image/hook.png');
  hook.width = 40
  hook.height = 40
  hook.pivot.set(180, 0) //偏移量
  hook.position.set(miner.position.x + minerDown.x, miner.position.y + minerDown.y)
  app.stage.addChild(hook)
  // 创建绳子
  rope = new PIXI.Graphics()
  app.stage.addChild(rope)
  updateRope()

  // 创建矿物 (放在下半部分)
  createMinerals()

  // 创建按钮 (底部)
  createButton()

  // 设置键盘监听
  window.addEventListener('keydown', handleKeyDown)
}

const triggerConfetti = () => {
  if (!gameCanvas.value) return
  const rect = gameCanvas.value.getBoundingClientRect();
 
 confetti({
   particleCount: 100,
   spread: 70,
   origin: {
     x: (rect.left + rect.width / 2) / window.innerWidth,
     y: (rect.top + rect.height / 2) / window.innerHeight
   }
 });
}

// 创建发射按钮
function createButton() {
  const button = new PIXI.Container()
  button.interactive = true

  // 背景状态
  const bgNormal = new PIXI.Graphics().roundRect(0, 0, 70, 70, 70).fill(0x4caf50)

  const bgPressed = new PIXI.Graphics().roundRect(0, 0, 70, 70, 70).fill(0xf44336)
  bgPressed.visible = false

  // 文字
  const text = new PIXI.Text({
    text: '发射',
    style: {
      fontFamily: 'Arial',
      fontSize: 20,
      fill: 0xffffff,
      fontWeight: 'bold',
    },
  })
  text.anchor.set(0.5)
  text.position.set(35, 35)

  // 组合元素
  button.addChild(bgNormal, bgPressed, text)

  // 事件绑定
  button.on('pointerdown', () => {
    bgNormal.visible = false
    bgPressed.visible = true
    text.style.fill = 0xffff00
  })

  const resetState = () => {
    bgNormal.visible = true
    bgPressed.visible = false
    text.style.fill = 0xffffff
    fireHandle()
  }

  button.on('pointerup', resetState)
  button.on('pointerupoutside', resetState)

  fireButton = button
  fireButton.position.set(canvasWidth / 2 - 35, canvasheight - 100)
  fireButton.visible = false
  app.stage.addChild(fireButton)
}

// 创建矿物 (放在下半部分)
const createMinerals = () => {
  minerals.forEach((mineral) => app.stage.removeChild(mineral))
  minerals = []

  const mineralTypes = [
    { color: 0xffd700, value: 500, size: 30, shape: 'circle' },
    { color: 0xffd700, value: 500, size: 30, shape: 'circle' },
    { color: 0xffd700, value: 500, size: 30, shape: 'circle' },
    { color: 0xc0c0c0, value: 300, size: 25, shape: 'circle' },
    { color: 0x8b0000, value: 100, size: 20, shape: 'rect' },
    { color: 0x000000, value: 50, size: 15, shape: 'rect' },
    { color: 0xc0c0c0, value: 100, size: 20, shape: 'circle' },
    { color: 0xc0c0c0, value: 50, size: 15, shape: 'circle' },
    { color: 0xffd700, value: 50, size: 15, shape: 'circle' },
  ]

  for (let i = 0; i < 10; i++) {
    const type = mineralTypes[Math.floor(Math.random() * mineralTypes.length)]
    const mineral = new PIXI.Graphics()

    if (type.shape === 'circle') {
      mineral.circle(0, 0, type.size)
    } else {
      mineral.rect(-type.size / 2, -type.size / 2, type.size, type.size)
    }

    mineral.fill(type.color)

    // 矿物放在下半部分 (y坐标更大)
    mineral.position.set(
      Math.random() * 360 + 10,
      Math.random() * 300 + 250, // 调整到下半部分
    )
      ; (mineral as unknown as TypeValue).value = type.value
    app.stage.addChild(mineral)
    minerals.push(mineral)
  }
}

// 游戏主循环
const gameLoop = () => {
  if (isPaused.value) return

  // 矿工简单动画
  minerAnimationFrame++
  if (minerAnimationFrame % 10 === 0) {
    miner.children[0].rotation = Math.sin(minerAnimationFrame / 10) * 0.1
  }

  // 更新钩子和绳子
  updateHookAndRope()

  // 检测碰撞
  if (hookState === 'extending') {
    checkCollisions()
  }
}

interface TypeValue {
  value?: number
  [key: string]: unknown // 允许其他未知属性
}

// 更新钩子和绳子 (调整为向下摆动和延伸)
const updateHookAndRope = () => {
  const minerCenter = {
    x: miner.position.x + minerDown.x,
    y: miner.position.y + minerBodyStyle.h, // 矿工底部位置
  }
  // 计算钩子位置（沿下半圆路径）
  const xOffset = Math.cos(hookAngle) * swingRadius
  const yOffset = Math.sin(hookAngle) * swingRadius
  if (hookState === 'swinging') {
    // 下半圆钟摆运动
    hookAngle += angularSpeed * direction
    // 限制角度在 0 到 π 之间（下半圆）
    if (hookAngle >= Math.PI || hookAngle <= 0) {
      direction = direction * -1 // 改变方向
    }

    hook.position.set(minerCenter.x + xOffset, minerCenter.y + yOffset)

    // 更新钩子旋转角度
    hook.rotation = hookAngle - Math.PI / 2
    // 更新绳子
    updateRope()
  } else if (hookState === 'extending') {
    // 钩子向下延伸
    hook.position.x += xOffset * hookSpeed * 0.05
    hook.position.y += yOffset * hookSpeed * 0.05

    // 更新绳子
    updateRope()

    // 检查是否超出屏幕底部
    if (hook.position.y > canvasheight || hook.position.x < 0 || hook.position.x > canvasWidth) {
      hookState = 'retracting'
    }
  } else if (hookState === 'retracting' || hookState === 'caught') {
    // 钩子向上收回
    const dx = minerCenter.x - hook.position.x
    const dy = minerCenter.y - hook.position.y
    const distance = Math.sqrt(dx * dx + dy * dy)

    if (distance < 10) {
      // 钩子回到矿工位置
      if (hookState === 'caught' && caughtMineral) {
        if (caughtMineral.value > 200) {
          triggerConfetti()
        }
        score.value += (caughtMineral as unknown as TypeValue)?.value ?? 0
        app.stage.removeChild(caughtMineral)
        caughtMineral = null
      }
      hookState = 'swinging'
    } else {
      // 向矿工移动
      const speed = hookState === 'caught' ? hookSpeed / 2 : hookSpeed
      hook.position.x += (dx / distance) * speed
      hook.position.y += (dy / distance) * speed

      // 如果捕获了矿物，一起移动
      if (caughtMineral) {
        caughtMineral.position.set(hook.position.x, hook.position.y + 20) // 矿物在钩子下方
      }

      // 更新绳子
      updateRope()
    }
  }
}

// 更新绳子
const updateRope = () => {
  rope.clear()
  rope.setStrokeStyle({
    width: 5,
    color: 0x8B4513,
    alpha: 0.9,
    cap: 'round',
    join: 'round'
  })
  rope.moveTo(miner.position.x + minerDown.x, miner.position.y + minerBodyStyle.h)
  rope.lineTo(hook.position.x, hook.position.y)
  rope.stroke()
}

// 检测碰撞
const checkCollisions = () => {
  for (const mineral of minerals) {
    if (!mineral.parent) continue

    const dx = hook.position.x - mineral.position.x
    const dy = hook.position.y - mineral.position.y
    const distance = Math.sqrt(dx * dx + dy * dy)

    const mineralSize =
      (mineral as unknown as TypeValue).value === 500
        ? 30
        : (mineral as unknown as TypeValue).value === 300
          ? 25
          : (mineral as unknown as TypeValue).value === 100
            ? 20
            : 15

    if (distance < mineralSize + 10) {
      hookState = 'caught'
      caughtMineral = mineral
      break
    }
  }
}

// 键盘控制
const handleKeyDown = (e: KeyboardEvent) => {
  if (e.code === 'Space' && hookState === 'swinging' && isGameRunning.value && !isPaused.value) {
    hookState = 'extending'
  }
}

const fireHandle = () => {
  console.log('发射！！！！-->')
  if (hookState === 'swinging' && isGameRunning.value && !isPaused.value) {
    hookState = 'extending'
  }
}

// 开始游戏
const startGame = () => {
  if (isGameRunning.value) return

  isGameRunning.value = true
  isPaused.value = false
  timeLeft.value = 60
  score.value = 0
  fireButton.visible = true
  gameInterval = app.ticker.add(gameLoop)
  timerInterval = window.setInterval(() => {
    if (!isPaused.value) {
      timeLeft.value--
      if (timeLeft.value <= 0) {
        endGame()
      }
    }
  }, 1000)
}

// 重置游戏
const resetGame = () => {
  app.destroy(true)
  endGame()
  initGame()
}

// 暂停/继续游戏
const togglePause = () => {
  if (!isGameRunning.value) return
  isPaused.value = !isPaused.value
  if (isPaused.value) {
    app.ticker.stop()
  } else {
    app.ticker.start()
  }
}

// 结束游戏
const endGame = () => {
  isGameRunning.value = false
  // app.ticker.remove(gameInterval)
  clearInterval(timerInterval)
}

// 生命周期钩子
onMounted(() => {
  initGame()
})

onUnmounted(() => {
  endGame()
  window.removeEventListener('keydown', handleKeyDown)
  if (gameCanvas.value && app) {
    gameCanvas.value.removeChild(app.view as HTMLCanvasElement)
    app.destroy()
  }
})
</script>

<style scoped>
.game-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: 20px;
}

.controls {
  margin-bottom: 20px;
  display: flex;
  gap: 10px;
  align-items: center;
}

button {
  padding: 8px 16px;
  cursor: pointer;
}

button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.game-canvas {
  border: 2px solid #333;
}
</style>
